
package com.org.controller;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.org.config.Configurations;
import com.org.entity.VideoEntity;
import com.org.util.ImageUtil;
import com.org.util.IoUtil;
import com.org.util.MD5Tools;
import com.org.util.Range;
import com.org.util.StreamException;
import com.org.util.TokenUtil;

import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.MultimediaInfo;

/**
 * 
 * 断点续传，支持多文件上传 上传工具主要代码来自Stream上传插件，详细情况百度查找相关文档即可
 * 
 * @author WangXiaoPeng
 *
 */
@Controller
public class ResumeUpLoadController {
	static final String FILE_NAME_FIELD = "name";
	static final String FILE_SIZE_FIELD = "size";
	static final String TOKEN_FIELD = "token";
	static final String SERVER_FIELD = "server";
	static final String SUCCESS = "success";
	static final String MESSAGE = "message";
	static final int BUFFER_LENGTH = 102400;
	static final String START_FIELD = "start";
	public static final String CONTENT_RANGE_HEADER = "content-range";
	static final String FILE_FIELD = "file";

	/**
	 * when the has read to 10M, then flush it to the hard-disk.
	 */

	@RequestMapping("index")
	public String index() {
		return "index";
	}

	@RequestMapping("tk")
	public void token(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		doOptions(req, resp);
		System.out.println("执行了tk");
		String name = req.getParameter(FILE_NAME_FIELD);
		String size = req.getParameter(FILE_SIZE_FIELD);
		String token = TokenUtil.generateToken(name, size);

		PrintWriter writer = resp.getWriter();

		JSONObject json = new JSONObject();
		try {
			json.put(TOKEN_FIELD, token);
			if (Configurations.isCrossed())
				json.put(SERVER_FIELD, Configurations.getCrossServer());
			json.put(SUCCESS, true);
			json.put(MESSAGE, "");
		} catch (JSONException e) {
		}
		/** TODO: save the token. */

		writer.write(json.toString());
	}

	@RequestMapping(value = "upload", method = RequestMethod.GET)
	public void upload(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		doOptions(req, resp);
		System.out.println("执行了get方法");
		final String token = req.getParameter(TOKEN_FIELD);
		final String size = req.getParameter(FILE_SIZE_FIELD);
		final String fileName = req.getParameter(FILE_NAME_FIELD);
		final PrintWriter writer = resp.getWriter();

		/** TODO: validate your token. */

		JSONObject json = new JSONObject();
		long start = 0;
		boolean success = true;
		String message = "";
		try {
			File f = IoUtil.getTokenedFile(token, "");
			start = f.length();
			/** file size is 0 bytes. */
			if (token.endsWith("_0") && "0".equals(size) && 0 == start)
				f.renameTo(IoUtil.getFile(fileName));
		} catch (FileNotFoundException fne) {
			message = "Error: " + fne.getMessage();
			success = false;
		} finally {
			try {
				if (success)
					json.put(START_FIELD, start);
				json.put(SUCCESS, success);
				json.put(MESSAGE, message);
			} catch (JSONException e) {
			}
			writer.write(json.toString());
			IoUtil.close(writer);
		}
	}

	@RequestMapping(value = "upload", method = RequestMethod.POST)
	public void upLoadPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doOptions(req, resp);
		System.out.println("执行了up的post方法");
		final String token = req.getParameter(TOKEN_FIELD);
		final String fileName = req.getParameter(FILE_NAME_FIELD);
		Range range = IoUtil.parseRange(req);

		OutputStream out = null;
		InputStream content = null;
		final PrintWriter writer = resp.getWriter();

		/** TODO: validate your token. */

		JSONObject json = new JSONObject();
		long start = 0;
		boolean success = true;
		String message = "";
		File f = null;
		String realPath = Configurations.getFileRepository() + File.separator;
		if (imgLocation(fileName)) {
			realPath += "picFile" + File.separator;
			f = IoUtil.getTokenedFile(token, "picFile" + File.separator);
		} else {
			f = IoUtil.getTokenedFile(token, "");
		}

		try {
			if (f.length() != range.getFrom()) {
				/** drop this uploaded data */
				throw new StreamException(StreamException.ERROR_FILE_RANGE_START);
			}

			out = new FileOutputStream(f, true);
			content = req.getInputStream();
			int read = 0;
			final byte[] bytes = new byte[BUFFER_LENGTH];
			while ((read = content.read(bytes)) != -1)
				out.write(bytes, 0, read);

			start = f.length();
		} catch (StreamException se) {
			success = StreamException.ERROR_FILE_RANGE_START == se.getCode();
			message = "Code: " + se.getCode();
		} catch (FileNotFoundException fne) {
			message = "Code: " + StreamException.ERROR_FILE_NOT_EXIST;
			success = false;
		} catch (IOException io) {
			message = "IO Error: " + io.getMessage();
			success = false;
		} finally {
			IoUtil.close(out);
			IoUtil.close(content);

			/** rename the file */
			if (range.getSize() == start) {
				/** fix the `renameTo` bug */
				// File dst = IoUtil.getFile(fileName);
				// dst.delete();
				// TODO: f.renameTo(dst); 重命名在Windows平台下可能会失败，stackoverflow建议使用下面这句
				try {
					// 先删除
					IoUtil.getFile(fileName).delete();
					String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
					String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
					Files.move(f.toPath(), f.toPath().resolveSibling(newFileName));
					/** if `STREAM_DELETE_FINISH`, then delete it. */
					if (Configurations.isDeleteFinished()) {
						IoUtil.getFile(fileName).delete();
					}
					File newfile = new File(realPath + newFileName);
					newfile.setReadable(true, false);
					String md5 = MD5Tools.getFileMD5(newfile);
					if (this.videoLocation(newFileName)) {
						//windows截图
						// makeScreenCut(realPath+newFileName,realPath+File.separator+newFileName+".jpg");
						//linux截图
						getThumbLinux(realPath + newFileName, realPath + newFileName + ".jpg");
						json.put("playtime", this.readVideo(newfile).getPlaytime());
						json.put("widthAndHeight", this.readVideo(newfile).getWidthAndHeight());
						json.put("thumb", Configurations.getVisitURL() + newFileName + ".jpg");
						json.put("type", "video");
						json.put("url", Configurations.getVisitURL() + newFileName);
						json.put("fileName", newFileName);
					} else if (suffix.endsWith("txt")) {
						json.put("type", "txt");
						json.put("fileName", newFileName);
					} else if (imgLocation(newFileName)) {
						BufferedImage sourceImg = ImageIO.read(new FileInputStream(newfile));
						// 执行压缩图片
						// ImageUtil.reduceImg(imgsrc, imgdist, widthdist, heightdist, rate);
						float widthAndHeight = (float) (sourceImg.getWidth() * 1.0 / sourceImg.getHeight());
						widthAndHeight = Float.parseFloat(new java.text.DecimalFormat("#.00").format(widthAndHeight));
						json.put("widthAndHeight", widthAndHeight);
						json.put("url", Configurations.getVisitURL() + "picFile/" + newFileName);
						json.put("fileName", "picFile/" + newFileName);
						json.put("type", "img");
					}
					json.put("md5", md5);

				} catch (IOException e) {
					success = false;
					message = "Rename file error: " + e.getMessage();
				}

			}
			try {
				if (success)
					json.put(START_FIELD, start);
				json.put(SUCCESS, success);
				json.put(MESSAGE, message);
			} catch (JSONException e) {
			}

			writer.write(json.toString());
			IoUtil.close(writer);
		}
	}

	@RequestMapping(value = "upload", method = RequestMethod.OPTIONS)
	public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println(req.getMethod());
		resp.setContentType("application/json;charset=utf-8");
		resp.setHeader("Access-Control-Allow-Headers", "Content-Range,Content-Type");
		resp.setHeader("Access-Control-Allow-Origin", Configurations.getCrossOrigins());
		resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
		System.out.println("执行了head属性赋值");
	}

	private VideoEntity readVideo(File source) {
		Encoder encoder = new Encoder();
		VideoEntity videoEntity = new VideoEntity();
		long ls = 0L;
		try {
			MultimediaInfo m = encoder.getInfo(source);
			int bitRate = m.getVideo().getBitRate();
			ls = m.getDuration() / 1000;
			double size = m.getVideo().getSize().getWidth() * 1.0 / m.getVideo().getSize().getHeight();
			if (size < 1.3) {
				videoEntity.setWidthAndHeight("4:3");
			} else if (size > 1.5) {
				videoEntity.setWidthAndHeight("16:9");
			}
			videoEntity.setBitRate(bitRate);
			videoEntity.setPlaytime(ls);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return videoEntity;
	}

	public boolean videoLocation(String fileName) throws IOException {
		String reg = "(mp4|flv|avi|rm|rmvb|wmv)";
		Pattern p = Pattern.compile(reg);
		boolean boo = p.matcher(fileName.toLowerCase()).find();
		return boo;
	}

	public boolean imgLocation(String fileName) throws IOException {
		String reg = "(jpg|png|gif|jpeg)";
		Pattern p = Pattern.compile(reg);
		boolean boo = p.matcher(fileName.toLowerCase()).find();
		return boo;
	}

	public void makeScreenCut(String videoRealPath, String imageRealName) {
		String ffmepgPath = Configurations.getConfig("FFMPEG_PATH");
		List<String> commend = new ArrayList<String>();
		commend.add(ffmepgPath);
		commend.add("-i");
		commend.add(videoRealPath);
		commend.add("-y");
		commend.add("-f");
		commend.add("image2");
		commend.add("-ss");
		commend.add("2");
		commend.add("-t");
		commend.add("0.001");
		commend.add(imageRealName);
		try {
			ProcessBuilder builder = new ProcessBuilder();
			builder.command(commend);
			builder.redirectErrorStream(true);
			System.out.println("视频截图开始...");

			Process process = builder.start();
			/*
			 * InputStream in = process.getInputStream(); byte[] bytes = new byte[1024];
			 * System.out.print("正在进行截图，请稍候"); while (in.read(bytes)!= -1){
			 * System.out.println("."); }
			 */
			System.out.println("");
			System.out.println("视频截取完成...");

		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("视频截图失败！");
		}
	}

	public static boolean getThumbLinux(final String videoRealPath, final String imageRealName) {
		String command = "/monchickey/ffmpeg/bin/ffmpeg -i " + videoRealPath + " -y -f image2 -ss 2 -t 0.001 " + imageRealName;
		String command2 ="/usr/bin/chmod  644 "+imageRealName;
		String[] cmd = new String[]{"/bin/sh","-c",command +"&&"+command2};
			try {
				Process pro=Runtime.getRuntime().exec(cmd);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		return true;
	}
}